// --------------------------------------------------------------------------------------------------
/*
eUI - 	EVISION FORM INTERACTIVE UI ELEMENTS
		0.1 Initial

*/
// --------------------------------------------------------------------------------------------------

function eUI() {

	// public vars
	this.targetForm = "default"; // form that will be eUI'ed
	this.debug = false; // debug mode, on or off	

	// private vars ---------------------------------------------------------------------------------
	var dataModel = {}; // internal object to store UI information
		
	dataModel['version'] = 1; // version of the model
	dataModel['name'] = 'eUI';
	dataModel['debug'] = false;
	dataModel['mode'] = 'standard'; // add a mode so that we can deal with any 'quirks'

	dataModel['modal'] = []; // modal window control
	
	dataModel['skin'] = [];	// skin & ui parameters and classes	
	
	dataModel['skin']['highlightEmpty'] = [];
	dataModel['skin']['highlightEmpty']['tableCells'] = 'td:empty';
	dataModel['skin']['highlightEmpty']['inputFields'] = 'input.form-control';
	
	dataModel['attlist'] = []; // list of data attributes that will be used
	dataModel['attlist']['hsSbRq'] = 'data-hassubreq'; 	// field has a sub-field that is a requirement (either defined or not)
	dataModel['attlist']['sbTrgt'] = 'data-subtrgt';	// sub-field that is the 'target'
	dataModel['attlist']['nullVal'] = 'data-nullvalue';	// field's 'null' or unset value
	dataModel['attlist']['sbNullVal'] = 'data-targetnull'; // sub-field's 'null' or empty value
	dataModel['attlist']['tglTrgt'] = 'data-tgltrgt'; // id of the element to be toggled (show/hide)
	dataModel['attlist']['fldType'] = 'data-fieldType'; // type of field - used in validation only
		
	dataModel['fieldList'] = {}; // list of fields that will be manipulated	
	
	// PUBLIC METHODS --------------------------------------------------------------------------------
	
	// initialisation
	this.init = function(_name) {
		post('init-start ----------------------------------------------------------------');
		// check for jQuery
		if (typeof jQuery === 'undefined') {post('noJQ');} else { var jq = jQuery.noConflict(); post('JQ avail');}
		if(this.targetForm == "default") {
			post('no TargetForm set');
		} else {
			// initialise elements
			dataModel['targetForm'] = this.targetForm;
			dataModel['name'] = _name;
			dataModel['debug'] = this.debug;
			buildFieldData();
			setUpSubFields();
			highlightBlanks();
			if(dataModel['debug']) {attachDebug();} // debug mode :)
			// add the onchange handler to keep the model updated
			jq('form :input').change(function(){
				updateModel(jq(this).attr('name'), jq(this).val(), jq(this).is(':checked'));
			});			
			// control the form submission
			overrideSubmit();			
			post('init-end --------------------------------------------------------------');
		}
	}
	
	// dump the Model
	this.dumpModel = function(_root) {
		_root = typeof _root !== 'undefined' ? _root: 'fieldList';
		console.dir(dataModel[_root]);
	}
	
	// check the form - public access to the private function
	this.checkForm = function() { validateForm();}	
	
	// PRIVATE METHODS ------------------------------------------------------------------------------
	
	// send alert to console
	var post = function(_msg, _indent) {
		_indent = typeof _indent !== 'undefined' ? _indent: 0;
		var indent = '';
		for (i=0; i < _indent; i++) {indent = indent + '     ';}
		if(dataModel['debug']) {
			console.log(dataModel['name'] + ': '+ indent + _msg);
		}		
	}
	
	// attach the debug Info
	var attachDebug = function() {
		var usage = '<span class=""><strong>Usage:</strong><br /><em>var evisionUI = new eUI(); <br />evisionUI.debug = true; <br />evisionUI.targetForm = "f";<br /> evisionUI.init("evisionUI");</em></span>';
		var style = 'position: absolute; clear: both; padding-top: 0px; bottom: 0; width: 100%; border-top: 1px solid rgb(143, 143, 143); background-color: rgb(250, 250, 250); padding: 10px; z-index:10000;';		
		var butDump = '<button type="button" id="dumpModel" onclick="' + dataModel['name'] + '.dumpModel()">Dump Model</button>';
		var butVal = '<button type="button" id="validateForm" onclick="' + dataModel['name'] + '.checkForm()">Validate Form</button>';
		var butClear = '<button type="button" id="clearCons" onclick="console.clear()">Clear Console</button>';
		var toInsert = '<div class="" style="' + style + '"><h4>' + dataModel['name'] + ':JQ Control / Debug</h5>' + butDump + '&nbsp;&nbsp;' + butVal + '&nbsp;&nbsp;' + butClear + '<br /><br />' + usage + '</div>';
		jq('body').prepend(toInsert);
	}
	
	// validate the form - PRIVATE
	var validateForm = function() {
		post('validateForm-start --------------------------------------------------------');
		// dumpModel('fieldList');
		var toReturn = false;
		var fieldCount = 0;
		var passCount = 0;
		var failCount = 0;
		var orphanSubFields = []; // array of sub fields that 'dont' count towards validation
		// loop over each field in the model
		for (var k in dataModel['fieldList']) {
			if (typeof dataModel['fieldList'][k] !== 'function') { // only deal with the data-elements
				post('field - ' + k, 1);
				if(dataModel['fieldList'][k]['validation'] == 'none') { // no validation
						post('no validation', 2);
						var fieldValid = true;
						var subFieldValid = true;
						passCount ++;
				} else { // validate based on type, handled by filed validate function
					var fieldValid = false;
					var subFieldValid = false;
					fieldValid = validateField(k, dataModel['fieldList'][k]['validation']);
					// update the fields isValid in the model
					dataModel['fieldList'][k]['isValidated'] = fieldValid;
					post('Check Self|' + k + ' - ' + fieldValid, 3);
					// does it require the sub field checking
					if(dataModel['fieldList'][k]['hasSubReq']) {
						//check the fields value is not equal to its null value (eg sub field is needed)
						var mVal = dataModel['fieldList'][k]['value']; post('mVal:' + mVal);
						var mNull = dataModel['fieldList'][k]['nullValue']; post('mNull:' + mNull)
						if(mVal == mNull) {post('mVal == mNull');}
						if (mVal != mNull && mVal != undefined && mVal != '') { post('here -->');
							var subField = dataModel['fieldList'][k]['subField'];
							var subFieldValidation = dataModel['fieldList'][subField]['validation'];
							var subFieldValid = validateField(subField, subFieldValidation);
							post('Check Sub Field|' + subField + ' - ' + subFieldValid, 3);
							// update the subfields isValid in the model
							dataModel['fieldList'][subField]['isValidated'] = subFieldValid;
							// update the parent field, if subField is NOT valid
							if(!subFieldValid){dataModel['fieldList'][k]['isValidated'] = false;}
						}else if(mVal == undefined){
							fieldValid = false;
							subFieldValid = false;
						}else {
							fieldValid = true;
							subFieldValid = true;
							orphanSubFields.push(subField);							
						}
						
					} else {
						subFieldValid = true;
					}
					
					if ((fieldValid) && (subFieldValid)) {
						passCount ++;
					} else {
						failCount ++;
					}
				}
				fieldCount++;
			}
		}
		if ((passCount + orphanSubFields.length) >= fieldCount) {
			toReturn = true;
		}		
		post('FORM STATUS - ' + passCount + '/' + fieldCount + '| failed:' + failCount + ' | Orphans:' + Object.keys(orphanSubFields).length + '||' +  toReturn) ;
		return toReturn;
		post('validateForm-end ----------------------------------------------------------');
	}
	
	// build the field list - PRIVATE
	var buildFieldData = function() {
		post('buildFieldData-start ------------------------------------------------------');
		// jquery selector for the relevant fields
		var fieldTag = "[" + dataModel['attlist']['hsSbRq'] + "]:input";
		// var fieldTag = ":input";
		// array of fields that we will be processing
		var c = 0; // index
		// loop over each of the form fields
		jq(fieldTag).each(function(i,v) {
			var fieldHasSubReq = true;
			var fieldName = jq(this).attr('name');
			var fieldType = jq(this).attr('type');
			var fieldValue = jq(this).val();
			var fieldToggleTarget = jq(this).attr(dataModel['attlist']['tglTrgt']);
			var fieldValidationType = 'default';
			
			// EXCEPTION FOR RADIO BUTTON - GET ':CHECKED' Value
			if (fieldType == 'radio') {
				fieldValue = jq(this).filter(':checked').val();
				fieldValidationType = 'radio';
			}
			
			var fieldNullVal = jq(this).attr(dataModel['attlist']['nullVal']);
			var fieldSubField = jq(this).attr(dataModel['attlist']['sbTrgt']);
			var fieldSubVal = ""; /* GET THE VALUE */
			var fieldSubFieldNullVal = jq(this).attr(dataModel['attlist']['sbNullVal']);
			
			// add the field to the datamodel
			if (fieldName != undefined) {
				dataModel['fieldList'][fieldName] = {
					index: i,
					name: fieldName,
					hasSubReq: fieldHasSubReq,
					type: fieldType,
					toggleTarget: fieldToggleTarget,
					validation: fieldValidationType,
					isValidated: false,
					value: fieldValue,
					valueType: '',
					nullValue: fieldNullVal,
					subField: fieldSubField,
					subNull: fieldSubFieldNullVal,
					subVal: fieldSubVal,
					parentField: 'null'
				}; i++;
			}

			// has subReq? add that to the model
			if (fieldHasSubReq == 1) {
				var fieldParent = fieldName;
				fieldName = fieldSubField;
				fieldType = jq("[name='" + fieldName + "']").attr('type');
				// post('-------TYPE:' + fieldType);
				if(fieldType == 'hidden') {
					var arr = fieldName.split('.');// question identifier taken from the hidden field ( last element in . delimited list)
					// post(arr[arr.length-1]);
				}
				fieldValidationType = fieldType;
				fieldValue = [];
				fieldNullVal = fieldSubFieldNullVal;
				
				dataModel['fieldList'][fieldName] = {
					index: i,
					name: fieldName,
					hasSubReq: false,
					type: fieldType,
					toggleTarget: 'null',
					validation: fieldValidationType,
					isValidated: false,
					value: fieldValue,
					valueType: '',
					nullValue: fieldNullVal,
					subField: 'null',
					subNull: 'null',
					subVal: 'null',
					parentField: fieldParent
				}; i++;			
			}
			
		});
		post('buildFieldData-complete ---------------------------------------------------');
	}	
	
	// update the data model
	var updateModel = function(_field, _value, _checked) {
		post('updateModel-start ---------------------------------------------------------');
		var _type = jq("[name='" + _field + "']").attr('type');
		post('FIELD:' + _field + ' | TYPE:' + _type + '| VALUE:' + _value + ' | CHECKED:' + _checked);
		if (_type == 'checkbox') {
			// get the correct fieldname to use
			var arr = _field.split('.');// question identifier taken from the hidden field ( last element in . delimited list)
			var arr2 = arr[arr.length-1].split('-');
			var i = arr2[arr2.length-1];
			var f = 'ANSWER.TTQ.MENSYS.' + i;
			dataModel['fieldList'][f]['valueType'] = _type;
			if (_checked) { post('checkbox');
				// post('add a value');				
				dataModel['fieldList'][f]['value'].push(_value);
			} else {
				// post('delete a value');
				var index = dataModel['fieldList'][f]['value'].indexOf(_value);
				if(index > -1) {
					dataModel['fieldList'][f]['value'].splice(index, 1);
				}
			}
			var parentField = dataModel['fieldList'][f]['parentField'];
		} else { post('not checkbox');
			dataModel['fieldList'][_field]['value'] = _value;
			dataModel['fieldList'][_field]['valueType'] = _type;
			var parentField = dataModel['fieldList'][_field]['parentField'];
		}
		// remove the error class if present
		jq("[name='" + _field + "']").closest('.form-group').removeClass('has-error');
		// if it is a sub-field in error, remove from parent as well
		if (parentField != 'null') {
			jq("[name='" + parentField + "']").closest('.form-group').removeClass('has-error');
		}
		
		post('updateModel-end -----------------------------------------------------------');
	}
	
	// setup the sub fields to either show or hide - PRIVATE
	var setUpSubFields = function() {
		post('setUpSubFields-start ------------------------------------------------------');
		// loop over the fields from the model
		for (var k in dataModel['fieldList']){
			if (typeof dataModel['fieldList'][k] !== 'function') {
				// post('working with-:' + k);
				var myVal = dataModel['fieldList'][k]['value'];
				var myNullVal = dataModel['fieldList'][k]['nullValue'];
				// post('myVal:' + myVal + ' | myNull:' + myNullVal);
				var myTrgt = dataModel['fieldList'][k]['subField'];
				// post('mytrgt:' + myTrgt);
				if((myVal == myNullVal) || (myVal == undefined)) {
					var toggleTarget = jq('#' + dataModel['fieldList'][k]['toggleTarget']);
					//post('toggleTarget:#' + toggleTarget.attr('id'));
					toggleTarget.hide(); 
				}
				// toggle buttons
				// radio
				jq("[name='" + k + "'][value='N']").click(function(){
					var t = dataModel['fieldList'][jq(this).attr('name')]['toggleTarget'];
					jq('#' + t).slideDown();					
				});
				jq("[name='" + k + "'][value='Y']").click(function(){
					var t = dataModel['fieldList'][jq(this).attr('name')]['toggleTarget'];
					post('--------------------->' + t);
					jq('#' + t).slideUp();					
				}); 
				post('                   ');
			}
		}	
		post('setUpSubFields-complete ---------------------------------------------------');
	}
	
	// Highlight the empty fields. Selectors defined in dataModel
	var highlightBlanks = function() {
		post('highlightBlanks-start -----------------------------------------------------');
			jq(dataModel['skin']['highlightEmpty']['inputFields']).each(function() {
				if(jq(this).val() == "") {jq(this).parent().addClass('has-error');}
			});
			jq(dataModel['skin']['highlightEmpty']['tableCells']).addClass('danger').text('');
			// jq('td:contains("<!--#ERROR-->")').addClass('danger');
		post('highlightBlanks-end -------------------------------------------------------');
	}
	
	// validate the field - PRIVATE
	var validateField = function(_field, _type) {
		post('validateField-start -------------------------------------------------------');
		var toReturn = false; // defaults to failed validation
		// switch based on _type of validation
		// post('field:' + _field + '| validation type:' + _type, 5);
		switch(_type) { 
			case "none":	// no validation
			case "null":
			
				break;
			
			case undefined: // undefined value
				// post(_field + ': special case, no type set');
				// console.dir(dataModel['fieldList'][_field]);
				// post(dataModel['fieldList'][_field]['type']);
				
				break;
			case "hidden": // hidden field (used by checkboxes)
				var v = dataModel['fieldList'][_field]['value'];
				if (typeof v == 'object') {
					if (v.length > 0) { toReturn = true; /**/ post(_field + ':valid', 5); }
				}				
			
				break;
			case "numeric": // valid number format only
				var v = dataModel['fieldList'][_field]['value'];
				toReturn = !isNaN(parseFloat(v)) && isFinite(v);
				break;
			
			case "string": // letters only
			
				break;
			
			case "email": // email address only
				var e = dataModel['fieldList'][_field]['value'];
				var regex = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
				return regex.test(e);
				break;
			
			case "radio": // radio button - make sure one is checked
				if(jq("[name='" + _field + "']").is(':checked')) { toReturn = true; /**/ post(_field + ':valid', 5); }				
				break;
	
			default:
				// just check on a value, not undefined or ""
				var fVal = 1;
				if((fVal != "") && (fVal != undefined)) { toReturn = true; }
		}
		// post('validation:' + toReturn);
		post('validateField-end ---------------------------------------------------------');
		return toReturn; // pass back the value	
	}	
	
	// override the default submit handler if required
	var overrideSubmit = function() {
		post('overrideSubmit-start ------------------------------------------------------');
		// post('working with form:' + dataModel['targetForm']);		
		jq('form[name="' + dataModel['targetForm'] + '"]').submit(function(event){ 
			post('CLICKED-SUBMIT --------------------------------------------------------');
			var canSubmit = validateForm();
			post('SUBMIT STATUS - ' + canSubmit);
			if(canSubmit) {
				if(dataModel['debug']){
					post('SW:SUBMISSION ALLOWED, STOPPED FOR TESTING');
					if(confirm('<debug>:To Continue, click OK')){}else{event.preventDefault();}
				}
			} else {
				event.preventDefault();
				flagErrors();
			}
		});		
		post('overrideSubmit-complete ---------------------------------------------------');
	}
	
	// highlight any fields with errors
	var flagErrors = function() {
		post('flagErrors-start ----------------------------------------------------------');
		var fList = [];
		for (var k in dataModel['fieldList']) {
			if (typeof dataModel['fieldList'][k] !== 'function') {
				if (!(dataModel['fieldList'][k]['isValidated'])) {
					post('NOT VALIDATED:' + k);
					fList.push(k);
					jq("[name='" + k + "']").closest('.form-group').addClass('has-error');
					var pField = dataModel['fieldList'][k]['parentField'];
					if((pField != 'null') && (dataModel['fieldList'][pField]['isValidated'] == false)) {
						jq("[name='" + dataModel['fieldList'][k]['parentField'] + "']").closest('.form-group').addClass('has-error');
					}
					
				}
			}		
		}
		var msg = 'Please ensure the highlighted fields (and any blue sub-fields) have been completed.'
		if(dataModel['debug']) { msg += '\r\n <debug>' + fList + ' </debug>'; }
		alert(msg);
		post('flagErrors-complete -------------------------------------------------------');
	}

}